#pragma region Copyright
/// <copyright>
/// Copyright (c) 2007 Ilia Shramko.
/// Released under the terms of the GNU General Public License.
/// </copyright>
#pragma endregion

#include "stdafx.h"

const wchar_t* MixingModeMutexName = L"MixingMode-577D9BFF-494D-40AA-85A5-7EFA66200F51";

VMRStateController::VMRStateController()
	: _vmrFilterGraph(NULL), _vmrInMixingMode(NULL), _mixingModeMutexLock(_mixingModeMutex, false)
{
	ATLTRACE_TS(atlTraceVMRStateController, TraceLevel::Verbose,
		"VMRStateController::VMRStateController() : [0x%08X]\r\n", this);

	_mixingModeMutex.Create(NULL, FALSE, MixingModeMutexName);
}

VMRStateController::~VMRStateController()
{
	ATLTRACE_TS(atlTraceVMRStateController, TraceLevel::Verbose,
		"VMRStateController::~VMRStateController([0x%08X])\r\n", this);

	ClearVMRState();
}

HRESULT VMRStateController::NotifyGraphChange(IFilterGraph* filterGraph)
{
	if(filterGraph == NULL) return E_INVALIDARG;

	if(!IsVMRStateSaved())
		return S_OK;

	HRESULT hr = HasFilterGraphChanged(filterGraph);
	if(FAILED(hr)) return hr;

    if(hr == S_FALSE)
	{
		// This notification came from the filter graph with VMR in mixing mode.
		// Scan graph for saved VMR filter. If it is not found then clear the state.
		hr = DirectShowUtility::FilterExists(filterGraph, _vmrInMixingMode);
		if(hr == S_OK) return hr;
		if(hr == S_FALSE)
		{
			ATLTRACE_TS(atlTraceVMRStateController, TraceLevel::Verbose,
				"VMRStateController::NotifyGraphChange([0x%08X]) : Clearing VMR state.\r\n", this);

			ClearVMRState();
			return S_OK;
		}

		ATLASSERT(SUCCEEDED(hr));
		return hr;
	}
	else
	{
		// This notification came from a new filter graph.
		// Ignore.
		return S_OK;
	}
}

HRESULT VMRStateController::NotifyMixingModeSet(IFilterGraph* filterGraph, IBaseFilter* vmrFilter)
{
	if(!_mixingModeMutex) return E_UNEXPECTED;

	if(IsVMRStateSaved())
		return S_OK;

	if(!_mixingModeMutexLock.Lock(10))
	{
		ATLASSERT(0);
	}

	return SaveVMRState(filterGraph, vmrFilter);
}

HRESULT VMRStateController::CanSetMixingMode()
{
	if(!_mixingModeMutex) return E_UNEXPECTED;

	if(!_mixingModeMutexLock.Lock(0))
		return S_FALSE;

	_mixingModeMutexLock.Unlock();
	return S_OK;
}


HRESULT VMRStateController::SaveVMRState(IFilterGraph* filterGraph, IBaseFilter* vmrFilter)
{
	if(filterGraph == NULL) return E_INVALIDARG;
	if(vmrFilter == NULL) return E_INVALIDARG;

	ATLTRACE_TS(atlTraceVMRStateController, TraceLevel::Verbose,
		"VMRStateController::SaveVMRState([0x%08X])\r\n", this);

	CComPtr<IUnknown> filterGraphUnk;
	HRESULT hr = filterGraph->QueryInterface(&filterGraphUnk);
	if(FAILED(hr)) return hr;

	CComPtr<IUnknown> vmrFilterUnk;
	hr = vmrFilter->QueryInterface(&vmrFilterUnk);
	if(FAILED(hr)) return hr;

	_vmrFilterGraph = filterGraphUnk.p; // don't adref just store the pointer.
	_vmrInMixingMode = vmrFilterUnk.p; // don't adref just store the pointer.

	return S_OK;
}

void VMRStateController::ClearVMRState()
{
	if(_mixingModeMutexLock.IsLocked())
		_mixingModeMutexLock.Unlock();

	_vmrFilterGraph = NULL;
	_vmrInMixingMode = NULL;
}

bool VMRStateController::IsVMRStateSaved()
{
	return _vmrFilterGraph != NULL && _vmrInMixingMode != NULL;
}

HRESULT VMRStateController::HasFilterGraphChanged(IFilterGraph* filterGraph)
{
	if(filterGraph == NULL) return E_INVALIDARG;

	CComPtr<IUnknown> filterGraphUnk;
	HRESULT hr = filterGraph->QueryInterface(&filterGraphUnk);
	if(FAILED(hr)) return hr;

	if(_vmrFilterGraph == filterGraphUnk.p)
		return S_FALSE;
	
	return S_OK;
}


